package org.jeecg.modules.online.graphreport.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.DataBaseConstant;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.DynamicDataSourceModel;
import org.jeecg.common.util.RestUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.common.util.dynamic.db.DataSourceCachePool;
import org.jeecg.common.util.dynamic.db.DynamicDBUtil;
import org.jeecg.modules.online.cgform.util.CgformUtil;
import org.jeecg.modules.online.cgreport.util.CgReportSqlUtil;
import org.jeecg.modules.online.graphreport.entity.OnlGraphreportHead;
import org.jeecg.modules.online.graphreport.entity.OnlGraphreportParams;
import org.jeecg.modules.online.graphreport.entity.OnlGraphreportTemplet;
import org.jeecg.modules.online.graphreport.entity.OnlGraphreportTempletItem;
import org.jeecg.modules.online.graphreport.mapper.OnlGraphreportHeadMapper;
import org.jeecg.modules.online.graphreport.service.*;
import org.jeecg.modules.online.graphreport.util.GraphreportUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import lombok.extern.slf4j.Slf4j;

/**
 * @Description: 图表报告
 * @Author:jeecg-boot
 * @Date: 2019-04-10
 * @Version:V1.0
 */
@Slf4j
@Service("onlGraphreportApiServiceImpl")
public class OnlGraphreportApiServiceImpl extends ServiceImpl<OnlGraphreportHeadMapper, OnlGraphreportHead> implements IOnlGraphreportApiService {

	@Autowired
	private IOnlGraphreportHeadService headService;
	@Autowired
	private IOnlGraphreportTempletService templetService;
	@Autowired
	private IOnlGraphreportTempletItemService templetItemService;
	@Autowired
	private IOnlGraphreportParamsService paramsService;



	@Override
	public Result<?> getTempletChartsData(String id) {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		// 根据templetId查询模板数据
		OnlGraphreportTemplet templet = templetService.getById(id);
		if (templet == null) {
			return Result.error("未找到对应实体");
		}
		resultMap.put("templet", templet);

		// 查询出当前模板的所有子项
		List<OnlGraphreportTempletItem> templetItems = templetItemService.selectByMainId(id);
		// selectByMainId(id);
		//update-begin-author:lvdandan date:20200929 for:LOWCOD-911online组合报表 配置页面是否显示 设置不勾选 无效
		templetItems = templetItems.stream().filter(item -> item.getIsShow().equals("1")).collect(Collectors.toList());
		//update-begin-author:lvdandan date:20200929 for:LOWCOD-911online组合报表 配置页面是否显示 设置不勾选 无效

		// 遍历子项进行分组
		Iterator<OnlGraphreportTempletItem> iterator = templetItems.iterator();

		List<Object> groups = new ArrayList<>();
		List<Object> group = null;

		Integer groupNum = null;
		String groupStyle = null;
		String groupTxt = null;
		while (iterator.hasNext()) {
			OnlGraphreportTempletItem templetItem = iterator.next();

			// 如果groupNum不匹配，则新建分组
			if (groupNum == null || !templetItem.getGroupNum().equals(groupNum)) {
				if (group != null) {
					groups.add(this.getGroupMap(groupNum, groupStyle, groupTxt, group));
				}
				group = new ArrayList<>();
				groupNum = templetItem.getGroupNum();
				groupStyle = templetItem.getGroupStyle();
				groupTxt = templetItem.getGroupTxt();
			}
			// 获取图表数据
			String code = templetItem.getGraphreportCode();
			OnlGraphreportHead head = headService.queryByCode(code);
			// 判断图表类型
			String graphreportType = templetItem.getGraphreportType();
			if (!"normal".equals(graphreportType)) {
				head.setGraphType(graphreportType);
			}
			// 获取数据
			Map<String, Object> chartMap = this.queryChartDataSource(head, null);
			group.add(chartMap);
		}
		//update-begin-author:lvdandan date:20200929 for:LOWCOD-911online组合报表 配置页面是否显示 设置不勾选 无效
		if(group != null && group.size()>0){
			groups.add(this.getGroupMap(groupNum, groupStyle, groupTxt, group));
		}
		//update-begin-author:lvdandan date:20200929 for:LOWCOD-911online组合报表 配置页面是否显示 设置不勾选 无效
		resultMap.put("groups", groups);
		return Result.ok(resultMap);
	}

	/** 获取分组对象 */
	private Map<String, Object> getGroupMap(int groupNum, String groupStyle, String groupTxt, List<?> group) {
		Map<String, Object> groupMap = new HashMap<String, Object>();
		groupMap.put("groupNum", groupNum);
		groupMap.put("groupStyle", groupStyle);
		groupMap.put("groupTxt", groupTxt);
		groupMap.put("charts", group);
		return groupMap;
	}

	/** 执行sql语句，获取图表数据 */
	@Override
	public Map<String, Object> queryChartDataSource(OnlGraphreportHead head, String paramString) {
		Map<String, Object> resultMap = this.headService.queryChartConfig(head);
		resultMap.put("head", head);
		// 判断数据模式是否是sql，如果是就执行sql语句
		String dataType = "sql";
		//如果数据模式为api，则调用api接口
		String apiType = "api";
		//获取request
		HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
		if (dataType.equals(head.getDataType())) {
			String sql = head.getCgrSql();
			String dbKey = head.getDbSource();

			//update-begin-author:shunjianlei date:20210422---- for:【LOWCOD-1269】online图表，如何定义查询条件，实际应用中，都会根据查询条件去过滤数据
			// 查询用户自定义参数
			Map<String, Object> selfParams = CgReportSqlUtil.getParameterMap(request);
			Map<String, Object> paramsMap = new HashMap<>();
			List<OnlGraphreportParams> paramList = paramsService.selectByMainId(head.getId());
			for (OnlGraphreportParams p : paramList) {
				//前端传值为了避免 SQL自带的参数和查询条件参数弄混了 故而将SQL自带的参数名加前缀:self_
				Object paramValue = selfParams.get("self_" + p.getParamName());
				String value = "";
				if (paramValue != null && StringUtils.isNotBlank(paramValue.toString())) {
					value = paramValue.toString();
				} else if (StringUtils.isNotBlank(p.getParamValue())) {
					// 如果为空就设置默认值
					value = p.getParamValue();
				}
				String paramExpress = "${" + p.getParamName() + "}";
				if (sql.indexOf(paramExpress) > 0) {
					if (value.startsWith("'") && value.endsWith("'")) {
						value = value.substring(1, value.length() - 1);
					}
					//如果sql语句中有 参数表达式直接替换就行
					sql = sql.replace(paramExpress, value);
				} else if (StringUtils.isNotBlank(value)) {
					// 如果sql语句中没有 并且该参数不为空 也处理
					paramsMap.put(p.getParamName(), value);
				}
			}
			// 拼装查询条件SQL
			String conditionSql = GraphreportUtil.getSplicingConditionSql(sql, paramString, paramsMap);
			//update-end-author:shunjianlei date:20210422---- for:【LOWCOD-1269】online图表，如何定义查询条件，实际应用中，都会根据查询条件去过滤数据

			//log.info("Online图表: 查询SQL:" + conditionSql);
			List<Map<String, Object>> listMap;
			// 判断是否配置了多数据源
			if (oConvertUtils.isEmpty(dbKey)) {
				//log.info("Online图表: 走了稳定逻辑");
				listMap = headService.executeSelete(conditionSql);
			} else {
				//log.info("Online图表: 走了多数据源逻辑");
				DynamicDataSourceModel dbSource = DataSourceCachePool.getCacheDynamicDataSourceModel(dbKey);
				listMap = DynamicDBUtil.findList(dbKey, conditionSql);
			}
			//手工将字段都转为小写，为了兼容各种数据库
			resultMap.put("data", CgformUtil.toLowerCasePageList(listMap));
		}else if(apiType.equals(head.getDataType())){
			String url = head.getCgrSql().trim();
			if(oConvertUtils.isEmpty(url)){
				resultMap.put("data", new ArrayList<>());
				return resultMap;
			}
			// 替换 sys_base_path
			url = url.replace("#{" + DataBaseConstant.SYS_BASE_PATH + "}", RestUtil.getBaseUrl());
			//判断是否为外链接
			if(!url.startsWith("http")){
				if(url.startsWith("/")){
					url = RestUtil.getBaseUrl() + url;
				}else{
					url = RestUtil.getBaseUrl() + "/" + url;
				}
			}

			//update-begin-author:shunjianlei date:20210422---- for:【LOWCOD-1269】online图表，如何定义查询条件，实际应用中，都会根据查询条件去过滤数据
			// 替换参数
			Map<String, Object> selfParams = CgReportSqlUtil.getParameterMap(request);
			List<OnlGraphreportParams> paramList = paramsService.selectByMainId(head.getId());
			for (OnlGraphreportParams p : paramList) {
				//前端传值为了避免 自带的参数和查询条件参数弄混了 故而将自带的参数名加前缀:self_
				Object paramValue = selfParams.get("self_" + p.getParamName());
				String value = "";
				if (paramValue != null && StringUtils.isNotBlank(paramValue.toString())) {
					value = paramValue.toString();
				} else if (StringUtils.isNotBlank(p.getParamValue())) {
					// 如果为空就设置默认值
					value = p.getParamValue();
				}
				String paramExpress = "${" + p.getParamName() + "}";
				if (url.indexOf(paramExpress) > 0) {
					if (value.startsWith("'") && value.endsWith("'")) {
						value = value.substring(1, value.length() - 1);
					}
					//如果url中有 参数表达式直接替换就行
					url = url.replace(paramExpress, value);
				}
			}
			// 替换系统内置变量
			url = QueryGenerator.convertSystemVariables(url);
			//update-end-author:shunjianlei date:20210422---- for:【LOWCOD-1269】online图表，如何定义查询条件，实际应用中，都会根据查询条件去过滤数据

			//log.info("Online图表: 查询url:" + url);
			// 设置请求header，传递token
			HttpHeaders headers = new HttpHeaders();
			headers.set(CommonConstant.X_ACCESS_TOKEN, TokenUtils.getTokenByRequest(request));
			//请求接口数据
			String object = RestUtil.request(url, HttpMethod.GET, headers, null, null, String.class).getBody();
			JSONObject json = JSONObject.parseObject(object);
			//手工将字段都转为小写，为了兼容各种数据库
			List<Map<String, Object>> listMap = (List<Map<String, Object>>) json.get("data");
			if (listMap != null) {
				resultMap.put("data", CgformUtil.toLowerCasePageList(listMap));
			} else {
				resultMap.put("data", new ArrayList<>());
			}
		}
		return resultMap;
	}

}
